package net.folab.fo.runtime;

import net.folab.fo.runtime.Call;

import net.folab.fo.runtime._fo._lang.__Boolean;
import net.folab.fo.runtime._fo._lang.__Integer;
import net.folab.fo.runtime._fo._lang.__Integer.Value;

public class __factorial extends Call.Impl<__Integer.Value, __Integer.Value> {

    public static final __factorial INSTANCE = new __factorial();

    private __factorial() {
        super("<factorial>");
    }

    @Override
    public Eval<__Integer.Value> callOnce(final Eval<__Integer.Value> i) {

        final Eval<__Boolean.Value> isLessThantTwo = __Integer.Value.__3c.bind(i).call(__Integer.INSTANCE.init(2));
        Eval<Value> __subtracted = __Integer.Value.__2d.bind(i).call(__Integer.INSTANCE.init(1));
        final Eval<__Integer.Value> __next = __factorial.INSTANCE.call(__subtracted);

        return new Eval.Impl<__Integer.Value>() {

            @Override
            public String toString() {
                return "__factorial.callOnce(" + i + ")";
            }


            @Override
            public __Integer.Value evalOnce() {

                EvalCall<Value, Call<Value, Value>> bindCondition = __Boolean.Value.__if(__Integer.Value.class).bind(isLessThantTwo);
                Eval<Call<Value, Value>> bindThen = bindCondition.call(__Integer.INSTANCE.init(1));
                Call<Value, Value> evalThen = bindThen.eval();
                Eval<Value> elseValue = __Integer.Value.__2a.bind(i).call(__next);
                Eval<Value> bindElse = evalThen.call(elseValue);
                return bindElse.eval();

            }

        };
    }


}
